/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 */

#include <rthw.h>
#include <rtconfig.h>

#include "bsp_print.h"
#include "ringbuff.h"

#ifndef RT_USING_FINSH
#error Please uncomment the line <#include "finsh_config.h"> in the rtconfig.h
#endif

#ifdef RT_USING_FINSH

static ringbuf serial_buf;                   /* 串口数据接收缓冲 */
static rt_mutex_t serial_tx_mutex = RT_NULL; /* 串口发送互斥锁 */

static void rt_hw_recv_cb(uint8_t ch, void *usr_param)
{
    ringbuf_t buf_ptr = (ringbuf_t)usr_param;

    RT_ASSERT(usr_param);

    if (!ringbuf_is_full(buf_ptr))
    {
        ringbuf_push(buf_ptr, &ch);
    }
}

int rt_hw_console_init(void)
{
    ringbuf_t buf_ptr = &serial_buf;

    /* 初始化串口接收缓冲 */
    ringbuf_init(buf_ptr);

    /* 初始化打印端口 */
    Bsp_Print_Init();

    /* 注册串口接收的用户处理回调 */
    Bsp_Print_RegisterRecvCallback(rt_hw_recv_cb, (void *)buf_ptr);

    return RT_EOK;
}
INIT_BOARD_EXPORT(rt_hw_console_init);

int rt_hw_console_init_mutex(void)
{
    if (!serial_tx_mutex)
    {
        /* 如果互斥锁没有初始化，则初始化互斥锁 */
        serial_tx_mutex = rt_mutex_create("console_tx", RT_IPC_FLAG_PRIO);
        RT_ASSERT(serial_tx_mutex);
    }

    return RT_EOK;
}
INIT_ENV_EXPORT(rt_hw_console_init_mutex);

/* 重定向rtthread nano的命令行输出到调试端口 */
void rt_hw_console_output(const char *str)
{
    rt_size_t i = 0, size = 0;

    RT_ASSERT(str);

    size = rt_strlen(str);
    if(serial_tx_mutex)
    {
        rt_mutex_take(serial_tx_mutex, RT_WAITING_FOREVER);
    }

    for (i = 0; i < size; i++)
    {
        if (*(str + i) == '\n')
        {
            Bsp_Print_Putc('\r');
        }
        Bsp_Print_Putc(*(str + i));
    }

    if(serial_tx_mutex)
    {
        rt_mutex_release(serial_tx_mutex);
    }
}

/* 获取调试端口的用户输入值 */
char rt_hw_console_getchar(void)
{
    /* Note: the initial value of ch must < 0 */
    int ch = -1;
    ringbuf_t buf_ptr = &serial_buf;

    if (!ringbuf_is_empty(buf_ptr))
    {
        ringbuf_pop(buf_ptr, &ch);
    }
    else
    {
        rt_thread_mdelay(10);
    }

    return ch;
}

#endif /* RT_USING_FINSH */
